/*
	course: CS 498
	author: Alex Jacob
	arrows.js Provides a class Circuit which instantiates a linear circuit with one branch 
	along a sequence of points provided to the constructor.
*/

var Circuit = function(canvID, points,circuitID, arrowSize, numArrows){
	this.on = true;
	this.canvasID = canvID;
	this.circuitID = circuitID;	//unique circuit ID
	this.svg = $('#' + this.canvasID).svg('get');
	this.circuitPath = this.svg.createPath();
	this.circuitPoints = points;
	this.numArrows = numArrows;
	
	if (arrowSize == 'small')
	{
		this.size = .4;
	}
	else if (arrowSize == 'medium')
	{
		this.size = .65;
	}
	else if (arrowSize == 'large')
	{
		this.size = .7;
	}
	else
	{
		this.size = .65;
	}
	
	this.circuitPath.move(this.circuitPoints[0][0],this.circuitPoints[0][1]);
	
	for (var i = 1; i < this.circuitPoints.length; i++)
	{
		this.circuitPath = this.circuitPath.line(this.circuitPoints[i][0],this.circuitPoints[i][1]);
	}
	this.svg.path(this.circuitPath, {fill: 'none', stroke: '#000000', strokeWidth: 1,id_:'circuit' + this.circuitID});
	
	this.circuitPathString = this.circuitPath.path();
	
	
	// determine length of linear path from pathstring
	var tmpCoords = this.circuitPathString.substring(1).split("L");
	this.circuitLength = 0.0;
	var x1,y1,x2,y2,tmpCurCoord;
	for (var i=1; i < tmpCoords.length; i++)
	{
		tmpPrevCoord = tmpCoords[i-1].split(",");
		tmpCurCoord = tmpCoords[i].split(",");
		x1 = parseFloat(tmpPrevCoord[0]);
		y1 = parseFloat(tmpPrevCoord[1]);
		x2 = parseFloat(tmpCurCoord[0]);
		y2 = parseFloat(tmpCurCoord[1]);
		this.circuitLength += Math.sqrt(Math.pow((x1-x2),2) + Math.pow((y1-y2),2));
	}
	
	
	/* getSwitchHandle returns an array A in this format:
		A[0] - x-coord. of midpoint of longest line segment in path
		A[1] - y-coord. of midpoint of longest line segment in path
		A[2] - slope of longest line segment in path
		A[3] - length of longest line segment in path
	*/
	this.getSwitchHandle = function() {
		var maxI = 0;
		var maxDist = 0;
		for (var i = 0; i < this.circuitPoints.length-1; i++)
		{
			var dist = Math.sqrt(Math.pow(this.circuitPoints[i][0]-this.circuitPoints[i+1][0],2)+Math.pow(this.circuitPoints[i][1]-this.circuitPoints[i+1][1],2))
			if (dist > maxDist)
			{
				maxDist = dist;
				maxI = i;
			}
		}
		var data = [(this.circuitPoints[maxI][0]+this.circuitPoints[maxI+1][0])/2,(this.circuitPoints[maxI][1]+this.circuitPoints[maxI+1][1])/2]
		data.push((this.circuitPoints[maxI][1]-this.circuitPoints[maxI+1][1])/(this.circuitPoints[maxI][0]-this.circuitPoints[maxI+1][0]));
		data.push(maxDist);
		return data;
		
		
	}
	
	
	/* hide() hides all the arrows moving across the circuit. */
	this.hide = function()
	{
		for (var i = 0; i < this.numArrows; i++)
		{
			this.arrows[i].setAttribute("visibility", "hidden");
		}
		
	}
	
	/* show() makes visible all the arrows moving across the circuit. */
	this.show = function()
	{
		for (var i = 0; i < this.numArrows; i++)
		{
			this.arrows[i].setAttribute("visibility", "inherited");
		}
		
	}
	
	/* setState() turns the circuit on or off depending on the boolean provided to it - when a circuit is off, its arrows will be hidden. */
	this.setState = function(bool)
	{
		if (bool)
		{
			this.on = true;
			this.show();
		}
		else
		{
			this.on = false;
			this.hide();
		}
	}
	
	/* initCircuit() initializes arrows and their animation along the circuit. */
	this.initCircuit = function()
	{
		//Circuit.Arrow signature (for reference) : canvasID,circuitID,arrowID,animDelay,arrowSize,circPathString
		this.arrows = new Array();
		for(var i = 0; i < this.numArrows;i++)
		{
			var delay = Math.floor(this.circuitLength*i);	//this one
			var newArrow = Circuit.Arrow(this.canvasID,this.circuitID,i,delay + 'ms',this.size,this.circuitPathString);
			newArrow.anim.setAttribute('dur',this.circuitLength*10+'ms');	//and this one
			//newArrow.svgArrow.setAttribute('visibility','hidden');
			this.arrows.push(newArrow.svgArrow);
		}
		
	}
	
	
	return this;
}

/* Arrow object - saves state for individual arrows along circuit. */
Circuit.Arrow = function(canvasID,circuitID,arrowID,animDelay,arrowSize,circPathString) {
	this.canvasID = canvasID;
	this.circuitID = circuitID;
	this.arrowID = arrowID;
	this.animDelay = animDelay;
	this.size = arrowSize;
	this.circuitPathString = circPathString;
	
	// initialize arrows in the containing SVG object
	
	this.elt = document.getElementById(this.canvasID).getElementsByTagName("svg")[0];
	this.group = document.createElementNS("http://www.w3.org/2000/svg", "g");
	this.group.setAttribute('id','group'+this.circuitID+"-"+this.arrowID);
	this.svgArrow = this.shape = document.createElementNS("http://www.w3.org/2000/svg", "path");
	this.shape.setAttribute('id','arrow'+this.circuitID+"-"+this.arrowID);
	this.anim = document.createElementNS("http://www.w3.org/2000/svg", "animateMotion");
	this.anim.setAttribute('id','anim'+this.circuitID+"-"+this.arrowID);
	this.setFill = document.createElementNS("http://www.w3.org/2000/svg", "set");
	this.setStroke = document.createElementNS("http://www.w3.org/2000/svg", "set");
	
	
	
	
	//this.group.setAttribute('transform','translate(20 30)');
	
	//this.shape.setAttribute('d',"M -30 -40 L -60 0 L -30 -10 L 0 0 z");
	this.shape.setAttribute('d',"M 0 -20 L -30 20 L 0 10 L 30 20 z");
	this.shape.setAttribute("fill", "white");
	this.shape.setAttribute("stroke", "white");
	this.shape.setAttribute("stroke-width", "3");
	this.shape.setAttribute("fill-opacity", ".50");
	this.shape.setAttribute("transform", "rotate(90 0 0)    scale(" + this.size + " " + this.size + ")");
	
	this.anim.setAttribute("path", this.circuitPathString);
	this.anim.setAttribute('begin',this.animDelay);
	//this.anim.setAttribute('dur','5000ms');
	this.anim.setAttribute('rotate','auto');
	this.anim.setAttribute('fill','freeze');	//does WHAT exactly?
	this.anim.setAttribute('repeatCount','indefinite');
	//this.group.setAttribute('visibility','inherited');
	
	/* This approach is admittedly a bit hackey - it would be ideal to 
	 just make arrows initially invisible, but I ran into trouble doing so so we'll use 
	 this for now. The problem it attempts to fix is that when arrows are initialized, but 
	 before they animate, they are visible in the upper left corner of the screen. It's ugly, 
	 but not a really big deal right now.
	 */
	
	this.setFill.setAttribute('attributeName','fill');
	this.setFill.setAttribute('begin',this.animDelay);
	//this.setFill.setAttribute('dur','0s');
	this.setFill.setAttribute('from','white');
	this.setFill.setAttribute('to','#00ee00');
	
	this.setStroke.setAttribute('attributeName','stroke');
	this.setStroke.setAttribute('begin',this.animDelay);
	//this.setStroke.setAttribute('dur','0s');
	this.setStroke.setAttribute('from','white');
	this.setStroke.setAttribute('to','#004400');
	
	this.shape.appendChild(this.setStroke);
	this.shape.appendChild(this.setFill);
	this.shape.appendChild(this.anim);
	this.group.appendChild(this.shape);
	this.elt.appendChild(this.group);
	
	return this;
}






